package com.zhouheng.springbootmultithreading.tuling.sync;

import org.openjdk.jol.info.ClassLayout;

/**
 * @author Fox
 * <p>
 * 关闭指针压缩（-XX:-UseCompressedOops）
 * 需要引入如下依赖
 * -XX:BiasedLockingStartupDelay=0 关闭偏向锁延迟
 * <dependency>
 * <groupId>org.openjdk.jol</groupId>
 * <artifactId>jol-core</artifactId>
 * <version>0.10</version>
 * </dependency>
 */
public class ObjectTest {

    public static void main(String[] args) throws InterruptedException {
        //jvm延迟偏向
//        Thread.sleep(5000);
//        new Object() 16字节，对象头Mark word 8字节 元数据指针4字节，无数组0字节，无示例数据0字节，对齐填充到8的整数倍，填充4字节，总共16字节
//        Object obj = new Object();
//        new Test() 24字节，对象头Mark word 8字节 元数据指针4字节，无数组0字节，示例数据long8字节+boolean1字节，对齐填充到8的整数倍，填充3字节，总共24字节
        Object obj = new Test();
//        new Integer[4] 16字节，对象头Mark word 8字节 元数据指针4字节，数组4字节，无示例数据0字节，对齐填充到8的整数倍，不需填充0字节，总共16字节
//        Object obj = new Integer[4];
        // obj.hashCode() 当对象可偏向时，MarkWord将变成未锁定状态，并只能升级成轻量锁
        // obj.hashCode();
        // 查看对象内部信息，可以看到对象的内存布局，以及低位存储锁的标记等信息
        // 锁标记为：001 无锁
        // -XX:BiasedLockingStartupDelay=0 关闭偏向延迟后， 为匿名偏向状态101，虽然是偏向状态但是未指定线程ID
        System.out.println(ClassLayout.parseInstance(obj).toPrintable());

        new Thread(() -> {
            //HotSpot 虚拟机在启动后有个 4s 的延迟才会对每个新建的对象开启偏向锁模式，但是这里锁的是类，早就创建了main里延迟4S，并不会让类的偏向锁生效
            // 这里虚拟机设置延迟时间为0S（-XX:BiasedLockingStartupDelay=0）或者先休眠4S后，锁状态就为偏向锁101了
            synchronized (obj) {
                // 偏向锁延迟原因，默认锁标记为：00 轻量级锁;
                // obj.hashCode() 当对象正处于偏向锁时，调用HashCode将使偏向锁强制升级成重量锁
//                obj.hashCode();
                /*try {
                    // wait是monitor的东西，偏向锁撤销会变为重量级锁
                    obj.wait(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }*/
                System.out.println(Thread.currentThread().getName() + "\n" + ClassLayout.parseInstance(obj).toPrintable());
            }

            //HotSpot 虚拟机在启动后有个 4s 的延迟才会对每个新建的对象开启偏向锁模式，但是这里锁的是类，早就创建了main里延迟4S，并不会让类的偏向锁生效
            // 所以类锁还是 00 轻量级锁
            /*synchronized (ObjectTest.class) {
                // 锁标记为：00 轻量级锁
                System.out.println(Thread.currentThread().getName()
                        + "\n" + ClassLayout.parseInstance(ObjectTest.class).toPrintable());
            }*/

            /*System.out.println(Thread.currentThread().getName() + "释放锁\n" + ClassLayout.parseInstance(obj).toPrintable());

            // jvm 优化
            try {
                Thread.sleep(100000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }*/

        }, "Thread1").start();

        // 线程休眠后，实际上线程2虽然也是偏向，但是指向的线程地址跟线程1是一样的，这里底层优化了，线程1不进行保活的话，直接用线程1重新给分配了线程2的任务去执行
//        Thread.sleep(2000);

        // 模拟轻微竞争场景2个线程抢锁，偏向锁膨胀为重量级锁
        /*new Thread(() -> {
            synchronized (obj) {
                System.out.println(Thread.currentThread().getName() + "\n" + ClassLayout.parseInstance(obj).toPrintable());
            }
        }, "Thread2").start();*/

    }
}

class Test {
    /**
     * 实例数据boolean 1字节
     */
    private boolean flag;
    /**
     * 实例数据 long 8字节
     */
    private long p;
}
